using UnityEngine;
using System;

namespace DanielSig.Geometry
{
	public struct ScalarVector32 : I32Bit
	{
		public static int Exponent = 6;
		
		public static implicit operator Quaternion(ScalarVector32 vector)
		{
			return Quaternion.AngleAxis(vector.Magnitude, vector.Unit);
		}
		public static implicit operator Plane(ScalarVector32 vector)
		{
			return new Plane(vector.Unit, vector.Magnitude);
		}
		public static implicit operator Vector3(ScalarVector32 vector)
		{
			return vector.Vector;
		}
		public static explicit operator Orientation32(ScalarVector32 vector)
		{
			return new Orientation32(vector.Vector);
		}
		public static explicit operator Coordinates32(ScalarVector32 vector)
		{
			return new Coordinates32(vector.Vector);
		}
		public static explicit operator Coordinates64(ScalarVector32 vector)
		{
			return new Coordinates64(vector.Vector);
		}
		
		public static explicit operator ScalarVector32(Vector3 vector)
		{
			return new ScalarVector32(vector);
		}
		public static explicit operator ScalarVector32(Quaternion quaternion)
		{
			float angle;
			Vector3 axis;
			quaternion.ToAngleAxis(out angle, out axis);
			return new ScalarVector32(axis, angle);
		}
		public static explicit operator ScalarVector32(Plane plane)
		{
			return new ScalarVector32(plane.normal, plane.distance);
		}
		public static explicit operator ScalarVector32(Orientation32 ori)
		{
			return new ScalarVector32(ori.vector);
		}
		public static explicit operator ScalarVector32(Coordinates32 coordinates)
		{
			return new ScalarVector32(coordinates.vector);
		}
		public static explicit operator ScalarVector32(Coordinates64 coordinates)
		{
			return new ScalarVector32(coordinates.vector);
		}
		
		
		public ScalarVector32(Vector3 vector)
		{
			_data = 0;
			this.Vector = vector;
		}
		public ScalarVector32(Vector3 unit, float magnitude)
		{
			_data = 0;
			if((unit.x * unit.x + unit.y * unit.y + unit.z * unit.z) != 1F)
			unit.Normalize();
			Unit = unit;
			Magnitude = magnitude;
		}
		public ScalarVector32(uint data)
		{
			_data = data;
		}
		
		public float Magnitude
		{
			get
			{
				uint m = (_data >> 16) & 0xFFFF;
				return m / ((float)(1<<Exponent));
			}
			set
			{
				uint m = (uint)(value * ((float)(1 << Exponent)));
				_data = (_data & 0xFFFF) | (m << 16);
			}
		}
		public Vector3 Unit
		{
			get
			{
				return new UnitVector16((ushort)(_data & 0xFFFF));
			}
			set
			{
				_data = (_data & 0xFFFF0000) | new UnitVector16(value).rawData;
			}
		}
		public Vector3 Vector
		{
			get
			{
				return Unit * Magnitude;
			}
			set
			{
				float len = value.magnitude;
				Magnitude = len;
				len = 1F / len;
				Unit = value * len;
			}
		}
		public uint rawData
		{
			get
			{
				return _data;
			}
			set
			{
				_data = value;
			}
		}
		
		private uint _data;
	}
}

